#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from __future__ import with_statement

import os
import yaml
import shutil

from oriolus.pith.packets.meta import Meta
from oriolus.pith.packets.packet import Packet
from oriolus.pith.packets.script import Script

class FileStorage:
    def __init__(self, path):
        self.__path = path
        if not os.path.exists(self.__path):
            os.mkdir(self.__path)

    def add(self, packet):
        self.__write_entry(packet)

        scripts_dir = os.path.join(self.__path, packet.name)
        if not os.path.exists(scripts_dir):
            os.mkdir(scripts_dir)
            
        scripts = []
        script_writer = ScriptWriter()
        for script in packet.scripts:
            scripts.append(script_writer.write(script, scripts_dir))
            
        return Packet(packet.meta, scripts, packet.status, packet.basepath)
            
    def __write_entry(self, packet):
        entry_name = self.__get_entry_name(packet.name)
        entry_path = os.path.join(self.__path, entry_name)

        writer = FilePacketEntryWriter()
        writer.write(packet, entry_path)

    @property
    def entries(self):
        return [self.__create_packet(file_name) for file_name in self.__find_entries()]

    def remove(self, packet_name):
        entry_name = os.path.join(self.__path, self.__get_entry_name(packet_name))
        #entries = [os.path.basename(entry_path) for entry_path in self.__find_entries()]
        entries = self.__find_entries()
        if not entry_name in entries:
            return
        
        os.remove(entry_name)
    
        packet_files = self.__find_scripts_for_entry(packet_name)
        [os.remove(file_path) for file_path in packet_files]
        
        os.rmdir(os.path.join(self.__path, packet_name))

    def update(self, packet):
        #self.remove(packet.name)
        #self.add(packet)
        self.__write_entry(packet)
        

    def __find_scripts_for_entry(self, packet_name):
        entries = []
        files_dir = os.path.join(self.__path, packet_name)
        for file_name in os.listdir(files_dir):
            entries.append(os.path.join(files_dir, file_name))

        return entries
    
    def __find_entries(self):
        entries = []
        filter = lambda x, y: x.endswith(y)
        mask = "ori.entry"
        for file_name in os.listdir(self.__path):
            if filter(file_name, mask):
                entries.append(os.path.join(self.__path, file_name))

        return entries

    def __get_entry_name(self, packet_name):
        return packet_name + ".ori.entry"

    def __get_script_file_name(self, packet_name, script_name):
        return "%s.%s" % (packet_name, script_name)

    def __create_packet(self, packet_name):
        result_packet = FilePacketEntryReader().read(packet_name);
        resources = self.__find_scripts_for_entry(result_packet.name)
        scripts = []
        for file_name in resources:
            if not file_name.endswith("ori.entry"):
                script = ScriptReader().read(file_name)
                scripts.append(script)

        return Packet(result_packet.meta, scripts, result_packet.status, result_packet.basepath)
        
class PacketEntryWriter:
    def write(packet):
        serialized_packet_entry = {
                   "name": packet.meta.name, 
                   "version": packet.meta.version,
                   "description": packet.meta.description, 
                   "conflicts": packet.meta.conflicts,
                   "replaces": packet.meta.replaces, 
                   "depends": packet.meta.depends, 
                   "status": packet.status,
                   "basepath": packet.basepath
                   }

        return yaml.dump(serialized_packet_entry, None, default_flow_style=False)
    
    write = staticmethod(write)
        

class FilePacketEntryWriter:
    def write(self, packet, file_path):
        with file(file_path, "w") as fd:
            fd.write(PacketEntryWriter.write(packet))

class PacketEntryReader:
    def read(stream):
        dict = yaml.load(stream)

        return Packet(
                  Meta(
                       dict["name"], 
                       dict["version"], 
                       dict["description"], 
                       dict["conflicts"], 
                       dict["replaces"], 
                       dict["depends"]
                   ), status=dict["status"], basepath=dict["basepath"])

    read = staticmethod(read)

class FilePacketEntryReader:
    def read(self, file_name):
        with file(file_name, "r") as fd:
            return PacketEntryReader.read(fd)


class ScriptReader:
    def read(self, file_name):
        name = os.path.basename(file_name).split('.')[-2]
        return Script(name, file_name)
        
class ScriptWriter:
    def write(self, script, destination_dir):
        destination_file = os.path.join(destination_dir, os.path.basename(script.path))
        shutil.copy(script.path, destination_file)
        return Script(script.name, destination_file)